package collectionx

import (
	"bytes"
	"fmt"
)

type Set[T comparable, V any] map[T]V

// NewSet 创建set
func NewSet[T comparable, V any](elements ...T) Set[T, V] {
	s := Set[T, V]{}
	for _, e := range elements {
		s.AddSelf(e)
	}
	return s
}
func NewSetMap[T comparable, V any](set Set[T, V]) Set[T, V] {
	s := Set[T, V]{}
	s.AddSetSelf(set)
	return s
}
func (r Set[T, V]) Len() int {
	return len(r)
}
func (r Set[T, V]) AddNew(elements ...T) Set[T, V] {
	setMap := NewSetMap(r)
	for _, v := range elements {
		var vs V
		(setMap)[v] = vs
	}
	return setMap
}
func (r Set[T, V]) AddSelf(elements ...T) Set[T, V] {
	for _, v := range elements {
		var vs V
		(r)[v] = vs
	}
	return r
}
func (r Set[T, V]) AddKVSelf(elements T, v V) Set[T, V] {
	(r)[elements] = v
	return r
}
func (r Set[T, V]) AddKV(elements T, v V) Set[T, V] {
	setMap := NewSetMap(r)
	setMap[elements] = v
	return setMap
}

func (r Set[T, V]) AddSetSelf(anotherSet Set[T, V]) Set[T, V] {
	for ele, v := range anotherSet {
		r.AddKVSelf(ele, v)
	}
	return r
}
func (r Set[T, V]) AddSet(anotherSet Set[T, V]) Set[T, V] {
	setMap := NewSetMap(r)
	for ele, v := range anotherSet {
		setMap.AddKVSelf(ele, v)
	}
	return setMap
}

// 无脑加，后替换前
func (r Set[T, V]) AddMapSelf(anotherMap map[T]V) {
	for k, v := range anotherMap {
		r.AddKVSelf(k, v)
	}
}
func (r Set[T, V]) Del(elements ...T) Set[T, V] {
	for _, v := range elements {
		delete(r, v)
	}
	return r
}
func (r Set[T, V]) Contain(element T) bool {
	_, ok := (r)[element]
	return ok
}

// IntersectSlice 获取 数组与map共同的元素
func (r Set[T, V]) IntersectSlice(anotherSet ...T) Set[T, V] {
	retSet := NewSet[T, V]()
	for _, ele := range anotherSet {
		if _, ok := (r)[ele]; ok {
			retSet.AddSelf(ele)
		}
	}
	return retSet
}

// IntersectSet 取交集
func (r Set[T, V]) IntersectSet(anotherSet Set[T, V]) Set[T, V] {
	retSet := NewSet[T, V]()
	for ele := range r {
		if v, ok := anotherSet[ele]; ok {
			retSet.AddKVSelf(ele, v)
		}
	}
	return retSet
}

// DiffSet IntersectSet 取差集
func (r Set[T, V]) DiffSet(anotherSet Set[T, V]) Set[T, V] {
	retSet := NewSet[T, V]()
	for key, value := range r {
		if _, ok := anotherSet[key]; !ok {
			retSet.AddKVSelf(key, value)
		}
	}
	return retSet
}

// ToSlice 获取所有元素的列表
func (r Set[T, V]) ToSlice() []T {
	//var retList []T
	retList := make([]T, 0, len(r))
	//retList := make([]T, len(r))
	for ele := range r {
		retList = append(retList, ele)
	}
	return retList
}
func (r Set[T, V]) ToVSlice() []V {
	//var retList []T
	retList := make([]V, 0, len(r))
	//retList := make([]T, len(r))
	for _, v := range r {
		retList = append(retList, v)
	}
	return retList
}

// ToString ToSlice 获取所有元素的列表
func (r Set[T, V]) ToString(separator string) string {
	var bt bytes.Buffer
	var count = 0
	for ele := range r {
		bt.WriteString(fmt.Sprint(ele))
		if count < r.Len() {
			bt.WriteString(separator)
		}
	}
	return bt.String()
}

// map 的key 转set (忽略value)
func MapKeyToSet[T comparable, V any](m map[T]V) Set[T, V] {
	set := NewSet[T, V]()
	for t, v := range m {
		set.AddKVSelf(t, v)
	}
	return set
}

// map value 转set (忽略value)
func MapReverse[T comparable, V comparable](m map[T]V) Set[V, T] {
	set := NewSet[V, T]()
	for k, v := range m {
		set.AddKVSelf(v, k)
	}
	return set
}
